﻿using MvvmCross.Platform;
using MvvmCross.Plugins.Messenger;
using MvvmCross.Core.ViewModels;
using Sidvall.Data;
using Sidvall.Serialization;
using Sidvall.WorkItemManager.UI.Entities;
using Sidvall.WorkItemManager.UI.Messaging;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;

namespace Sidvall.WorkItemManager.UI.ViewModels
{
    public partial class MonitorContextViewModel
    {
        #region Public Members

        #region CanEdit

        private bool _CanEdit;
        public bool CanEdit
        {
            get
            {
                return _CanEdit;
            }
            set
            {
                if (_CanEdit == value)
                    return;
                _CanEdit = value;
                RaisePropertyChanged(nameof(CanEdit));
            }
        }

        #endregion
        #region Context

        private string _Context;
        public string Context
        {
            get
            {
                return _Context;
            }
            set
            {
                if (_Context == value)
                    return;
                _Context = value;
                RaisePropertyChanged("Context");
                OnContextChanged();
            }
        }

        #endregion
        #region ActiveMonitoredWorkItem

        private MonitoredWorkItem _ActiveMonitoredWorkItem;
        public MonitoredWorkItem ActiveMonitoredWorkItem
        {
            get
            {
                return _ActiveMonitoredWorkItem;
            }
            set
            {
                if (_ActiveMonitoredWorkItem != null)
                    _ActiveMonitoredWorkItem.PropertyChanged -= OnActiveMonitoredWorkItemPropertyChanged;
                _ActiveMonitoredWorkItem = value;
                if (_ActiveMonitoredWorkItem != null)
                    _ActiveMonitoredWorkItem.PropertyChanged += OnActiveMonitoredWorkItemPropertyChanged;
                RaisePropertyChanged("ActiveMonitoredWorkItem");
                InitializeActiveWorkItem();
            }
        }

        #endregion
        #region ActiveWorkItem

        private WorkItem _ActiveWorkItem;
        public WorkItem ActiveWorkItem
        {
            get
            {
                return _ActiveWorkItem;
            }
            set
            {
                _ActiveWorkItem = value;
                RaisePropertyChanged("ActiveWorkItem");
            }
        }

        #endregion
        #region MonitoredWorkItemListIsVisible

        public bool MonitoredWorkItemListIsVisible
        {
            get
            {
                return _MonitoredWorkItemListIsVisible;
            }
            set
            {
                _MonitoredWorkItemListIsVisible = value;
                RaisePropertyChanged("MonitoredWorkItemListIsVisible");
            }
        }

        #endregion
        #region WorkItems

        private WorkItemCollection _WorkItems;
        public WorkItemCollection WorkItems
        {
            get
            {
                return _WorkItems;
            }
            set
            {
                _WorkItems = value;
                RaisePropertyChanged("WorkItems");
            }
        }

        #endregion
        #region ConnectionTypes

        private Sidvall.Data.KeyValueCollection<string, Data.ConnectionType> _ConnectionTypes;
        public Sidvall.Data.KeyValueCollection<string, Data.ConnectionType> ConnectionTypes
        {
            get
            {
                if (_ConnectionTypes == null)
                    this.ConnectionTypes = Sidvall.Data.KeyValueManager.FromEnum<Sidvall.WorkItemManager.Data.ConnectionType>();
                return _ConnectionTypes;
            }
            set
            {
                _ConnectionTypes = value;
                RaisePropertyChanged("ConnectionTypes");
            }
        }

        #endregion
        #region ComparisonOperators

        private Sidvall.Data.KeyValueCollection<string, Sidvall.Data.ComparisonOperator> _ComparisonOperators;
        public Sidvall.Data.KeyValueCollection<string, Sidvall.Data.ComparisonOperator> ComparisonOperators
        {
            get
            {
                if (_ComparisonOperators == null)
                    this.ComparisonOperators = Sidvall.Data.KeyValueManager.FromEnum<Sidvall.Data.ComparisonOperator>();
                return _ComparisonOperators;
            }
            set
            {
                _ComparisonOperators = value;
                RaisePropertyChanged("ComparisonOperators");
            }
        }

        #endregion
        #region ShowRemoteConnection

        public bool ShowRemoteConnection
        {
            get
            {
                if (this.ActiveEntity == null)
                    return false;
                if (this.ActiveEntity.ConnectionTypeId == Data.ConnectionType.RemoteAccess)
                    return true;
                return false;
            }
        }

        #endregion

        // Commands
        #region AddMonitoredWorkItemCommand

        public ICommand AddMonitoredWorkItemCommand
        {
            get
            {
                return new MvxCommand(AddMonitoredWorkItem);
            }
        }
        public void AddMonitoredWorkItem()
        {
            if (this.ActiveEntity == null)
                return;
            var item = new MonitoredWorkItem()
            {
                IsEnabled = true,
            };
            if (this.ActiveEntity.MonitorContextId != null)
                item.MonitorContextId = this.ActiveEntity.MonitorContextId.Value;
            this.ActiveEntity.MonitoredWorkItems.Add(item);
            this.ActiveMonitoredWorkItem = item;
            this.MonitoredWorkItemListIsVisible = false;
        }

        #endregion
        #region DeleteMonitoredWorkItemCommand

        public ICommand DeleteMonitoredWorkItemCommand
        {
            get
            {
                return new MvxCommand<MonitoredWorkItem>(DeleteMonitoredWorkItem);
            }
        }
        public void DeleteMonitoredWorkItem(MonitoredWorkItem item)
        {
            if (this.ActiveEntity == null)
                return;
            if (item == null)
                return;
            this.ActiveEntity.MonitoredWorkItems.Remove(item);
        }

        #endregion
        #region EditMonitoredWorkItemCommand

        public ICommand EditMonitoredWorkItemCommand
        {
            get
            {
                return new MvxCommand<MonitoredWorkItem>(EditMonitoredWorkItem);
            }
        }
        public void EditMonitoredWorkItem(MonitoredWorkItem item)
        {
            if (this.ActiveEntity == null)
                return;
            if (item == null)
                return;
            this.ActiveMonitoredWorkItem = item;
            this.MonitoredWorkItemListIsVisible = false;
        }

        #endregion
        #region ShowMonitoredWorkItemListCommand

        public ICommand ShowMonitoredWorkItemListCommand
        {
            get
            {
                return new MvxCommand(ShowMonitoredWorkItemList);
            }
        }
        public void ShowMonitoredWorkItemList()
        {
            this.ActiveEntity.MonitoredWorkItems.LoadDescription(this.WorkItems);
            this.MonitoredWorkItemListIsVisible = true;
        }

        #endregion
        #region ConnectToServerCommand

        public ICommand ConnectToServerCommand
        {
            get
            {
                return new MvxCommand(async () => await ConnectToServerAsync());
            }
        }
        public async Task ConnectToServerAsync()
        {
            MonitoredWorkItem activeMonitoredWorkItem;

            if (this.ActiveEntity == null)
                return;
            using (var busyManager = new BusyManager(this))
            {
                try
                {
                    if (this.ActiveMonitoredWorkItem != null)
                    {
                        activeMonitoredWorkItem = this.ActiveMonitoredWorkItem;
                        this.ActiveMonitoredWorkItem = null;
                    }
                    else
                    {
                        activeMonitoredWorkItem = null;
                    }
                    var serverConnection = Sidvall.WorkItemManager.SystemContextConfig.Current.EntityFacade.ServerConnectionManager.CreateServerConnection(this.ActiveEntity);
                    var includedEntities = new List<Data.Relations.WorkItemRelation>();
                    includedEntities.Add(Data.Relations.WorkItemRelation.WorkItemSensors);
                    if (serverConnection != null)
                        this.WorkItems = await Sidvall.WorkItemManager.UI.SystemContext.Current.DataPortal.WorkItemManager.GetItemsAsync(serverConnection, includedEntities);
                    else
                        this.WorkItems = await Sidvall.WorkItemManager.UI.SystemContext.Current.DataPortal.WorkItemManager.GetItemsAsync(this.ServerConnectionId, includedEntities);
                    this.ActiveEntity.MonitoredWorkItems.LoadDescription(this.WorkItems);
                    if (activeMonitoredWorkItem != null)
                        this.ActiveMonitoredWorkItem = activeMonitoredWorkItem;
                }
                catch (System.Exception ex)
                {
                    await Sidvall.UI.SystemContext.Current.DialogManager.ShowErrorMessageAsync("Export Error", ex);
                }
            }
        }

        #endregion

        #region OnActiveEntityChanged

        protected override void OnActiveEntityChanged(Sidvall.Business.BusinessObjectChangeMode changeMode, Sidvall.Business.ChildChangedEventArgs childArgs, System.ComponentModel.PropertyChangedEventArgs propertyArgs)
        {
            if (this.ActiveEntity.MonitoredWorkItems == null)
                this.ActiveEntity.MonitoredWorkItems = new MonitoredWorkItemCollection();
            this.Context = MonitorContext.Serialize(this.ActiveEntity);
            RaisePropertyChanged("ShowRemoteConnection");
        }

        #endregion
        #region OnContextChanged

        protected virtual void OnContextChanged()
        {
            if (this.PublishChange)
            {
                var message = new WorkItemContextMessage(this)
                {
                    Context = this.Context,
                    CanEdit = this.CanEdit,
                };
                Publish(message);
            }
        }

        #endregion
        #region OnViewEvent

        protected override async Task OnViewEventAsync(Sidvall.UI.Views.ViewEventArgs args)
        {
            if (this.IsSavable)
                this.IsSavable = false;
            await base.OnViewEventAsync(args);
        }

        #endregion

        #region Init

        public void Init(ContextParameter item)
        {
            this.ContextParameter = item;
        }

        #endregion
        #region InitializeContext

        public virtual void InitializeContext()
        {
            this.ActiveEntity = MonitorContext.Deserialize(this.Context);
        }

        #endregion
        #region StartAsync

        protected override async Task StartAsync()
        {
            _MonitoredWorkItemListIsVisible = true;

            var messenger = Mvx.Resolve<IMvxMessenger>();
            this.ViewModelResources.Add(messenger.Subscribe<WorkItemContextMessage>(OnWorkItemContextMessage));

            if (this.ContextParameter != null)
            {
                this.PublishChange = false;
                this.Context = this.ContextParameter.Context;
                this.ServerConnectionId = this.ContextParameter.ServerConnectionId.ToNullableInt32().Value;
                this.PublishChange = true;
                InitializeContext();
                this.ContextParameter = null;
            }
            await ConnectToServerAsync();
        }

        #endregion

        #endregion
        #region Private Members

        private bool _MonitoredWorkItemListIsVisible = false;

        private ContextParameter ContextParameter { get; set; }
        private int ServerConnectionId { get; set; }
        private bool PublishChange { get; set; }

        #region InitializeActiveWorkItem

        private void InitializeActiveWorkItem()
        {
            if (this.ActiveMonitoredWorkItem == null)
            {
                this.ActiveWorkItem = null;
            }
            else
            {
                this.ActiveWorkItem = (from o in this.WorkItems
                                       where o.WorkItemId == this.ActiveMonitoredWorkItem.WorkItemId
                                       select o).FirstOrDefault();
            }
        }

        #endregion

        #region OnActiveMonitoredWorkItemPropertyChanged

        private void OnActiveMonitoredWorkItemPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            InitializeActiveWorkItem();
        }

        #endregion
        #region OnWorkItemContextMessage

        private void OnWorkItemContextMessage(WorkItemContextMessage item)
        {
            this.CanEdit = item.CanEdit;
            if (this.Context == item.Context)
                return;
            this.PublishChange = false;
            this.Context = item.Context;
            this.PublishChange = true;
            InitializeContext();
            if (this.ActiveEntity != null)
                this.ActiveEntity.MonitoredWorkItems.LoadDescription(this.WorkItems);
        }

        #endregion

        #endregion
    }
}
